#ifndef _RINGQUEUE_HPP_
#define _RINGQUEUE_HPP_

#include <vector>

#include "Mutex.hpp"
#include "sem.hpp"

using namespace MyMutex;
using namespace SemModule;

//环形队列实现的整体框架是最后一个节点不放数据，_p_step %= _cap;  维护队列的同时，走到最后一个节点，步数回到0

//构造函数生产消费整体思想 
//生产者关注节点 有没有空 初始化 5  五个空节点  
//实现 -> 生产一个数据，生产者信号 -1 生产完给消费者发送信号 消费者信号 +1

//消费者关注节点 有没有数据 初始化 0 没有数据
//实现 ->消费一个数据，消费者信号 -1 消费完给生产者发送信号 生产者信号 +1


static const int initvalue = 5;

template <class T>
class RingQueue
{
public:

    RingQueue(int value = 5)
        : _cap(value),
          _rq(_cap),
          _blank_sem(_cap),
          _p_step(0),
          _data_sem(0),
          _c_step(0)
    {}

    // 生产
    void EQueue(T &in)
    {
        // 1.开始生产 (生产者信号 -1 )
        _blank_sem.P();
        // 2.加锁
        // 已经封装好的锁，使用完毕自动解锁
        LockGuard mutex_gurad(pmutex);

        _rq[_p_step] = in; // 生产
        ++_p_step;         //更新下标
        _p_step %= _cap;   // 维护环形队列


        // 3.给消费者信号
        _data_sem.V();

    }
    // 消费
    T& Pop()
    {
        //1.开始消费 (信号量 -1)
        _data_sem.P();
        
        // 2.加锁
        // 已经封装好的锁，使用完毕自动解锁
        LockGuard mutex_gurad(cmutex);

        //3.消费数据
        _t = _rq[_c_step];

        ++_c_step;           //更新下标  
        _c_step %= _cap;    //维持环形队列


        //4.给生产者信号
        _blank_sem.V();
        return _t;
    }


    ~RingQueue()
    {}

private:
    int _cap;           // 队列长度
    std::vector<T> _rq; // 环形队列结构

    // 生产者
    Sem _blank_sem; // 生产者关注是否为空
    int _p_step;    // 生产者走的步数
    // 消费者
    Sem _data_sem; // 消费者关注是否有数据
    int _c_step;   // 消费者走的步数

    // 生产 消费 两把锁
    Mutex pmutex;
    Mutex cmutex;

    T _t;    //消费者拿到的信号
};

#endif
